#include <sys/epoll.h>
#include "event_dispatcher.h"
#include "event_loop.h"
#include "log.h"

#define MAXEVENTS 128

// epoll 派发数据
typedef struct
{
    int event_count;            // 事件个数
    int nfds;                   // fd 个数
    int realloc_copy;           // 重新分配的次数
    int efd;                    // epoll fd
    struct epoll_event *events; // epoll 事件
} epoll_dispatcher_data;

static void *epoll_init(struct event_loop *);

static int epoll_add(struct event_loop *, struct channel *channel1);

static int epoll_del(struct event_loop *, struct channel *channel1);

static int epoll_update(struct event_loop *, struct channel *channel1);

static int epoll_dispatch(struct event_loop *, struct timeval *);

static void epoll_clear(struct event_loop *);

// epoll 实现的事件派发器
const struct event_dispatcher epoll_dispatcher = {
    "epoll",
    epoll_init,
    epoll_add,
    epoll_del,
    epoll_update,
    epoll_dispatch,
    epoll_clear,
};

// 初始化
void *epoll_init(struct event_loop *eventLoop)
{
    epoll_dispatcher_data *epollDispatcherData = malloc(sizeof(epoll_dispatcher_data));

    epollDispatcherData->event_count = 0;
    epollDispatcherData->nfds = 0;
    epollDispatcherData->realloc_copy = 0;
    epollDispatcherData->efd = 0;

    epollDispatcherData->efd = epoll_create1(0); // 新建 epoll
    if (epollDispatcherData->efd == -1)
    {
        error(1, errno, "epoll create failed");
    }
    // 初始化事件
    epollDispatcherData->events = calloc(MAXEVENTS, sizeof(struct epoll_event));

    return epollDispatcherData;
}

// 给 channel 添加监听事件
int epoll_add(struct event_loop *eventLoop, struct channel *channel1)
{
    epoll_dispatcher_data *pollDispatcherData = (epoll_dispatcher_data *)eventLoop->event_dispatcher_data;

    int fd = channel1->fd; // channel 对应的 fd
    int events = 0;
    if (channel1->events & EVENT_READ)
    {
        events = events | EPOLLIN; // 可读
    }
    if (channel1->events & EVENT_WRITE)
    {
        events = events | EPOLLOUT; // 可写
    }

    struct epoll_event event;
    event.data.fd = fd;
    event.events = events;
    //    event.events = events | EPOLLET;
    if (epoll_ctl(pollDispatcherData->efd, EPOLL_CTL_ADD, fd, &event) == -1)
    {
        error(1, errno, "epoll_ctl add  fd failed");
    }

    return 0;
}

// 给 channel 删除监听事件
int epoll_del(struct event_loop *eventLoop, struct channel *channel1)
{
    epoll_dispatcher_data *pollDispatcherData = (epoll_dispatcher_data *)eventLoop->event_dispatcher_data;

    int fd = channel1->fd;

    int events = 0;
    if (channel1->events & EVENT_READ)
    {
        events = events | EPOLLIN;
    }

    if (channel1->events & EVENT_WRITE)
    {
        events = events | EPOLLOUT;
    }

    struct epoll_event event;
    event.data.fd = fd;
    event.events = events;
    // event.events = events | EPOLLET;
    if (epoll_ctl(pollDispatcherData->efd, EPOLL_CTL_DEL, fd, &event) == -1)
    {
        error(1, errno, "epoll_ctl delete fd failed");
    }

    return 0;
}

// 给 channel 更新监听事件
int epoll_update(struct event_loop *eventLoop, struct channel *channel1)
{
    epoll_dispatcher_data *pollDispatcherData = (epoll_dispatcher_data *)eventLoop->event_dispatcher_data;

    int fd = channel1->fd;

    int events = 0;
    if (channel1->events & EVENT_READ)
    {
        events = events | EPOLLIN;
    }

    if (channel1->events & EVENT_WRITE)
    {
        events = events | EPOLLOUT;
    }

    struct epoll_event event;
    event.data.fd = fd;
    event.events = events;
    //    event.events = events | EPOLLET;
    if (epoll_ctl(pollDispatcherData->efd, EPOLL_CTL_MOD, fd, &event) == -1)
    {
        error(1, errno, "epoll_ctl modify fd failed");
    }
    return 0;
}

// 事件派发，其实就是 epoll_wait
int epoll_dispatch(struct event_loop *eventLoop, struct timeval *timeval)
{
    epoll_dispatcher_data *epollDispatcherData = (epoll_dispatcher_data *)eventLoop->event_dispatcher_data;
    int i, n;
    // 调用 epoll_wait 等待事件触发
    n = epoll_wait(epollDispatcherData->efd, epollDispatcherData->events, MAXEVENTS, -1);
    yolanda_msgx("epoll_wait wakeup, %s", eventLoop->thread_name);
    for (i = 0; i < n; i++) // 依次处理事件
    {
        // 如果当前事件发生错误，或者连接关闭
        if ((epollDispatcherData->events[i].events & EPOLLERR) || (epollDispatcherData->events[i].events & EPOLLHUP))
        {
            fprintf(stderr, "epoll error\n");
            close(epollDispatcherData->events[i].data.fd); // 记得关闭资源
            continue;
        }
        // 读事件
        if (epollDispatcherData->events[i].events & EPOLLIN)
        {
            yolanda_msgx("get message channel fd==%d for read, %s", epollDispatcherData->events[i].data.fd, eventLoop->thread_name);
            channel_event_activate(eventLoop, epollDispatcherData->events[i].data.fd, EVENT_READ); // 触发 channel 读事件
        }
        // 写事件
        if (epollDispatcherData->events[i].events & EPOLLOUT)
        {
            yolanda_msgx("get message channel fd==%d for write, %s", epollDispatcherData->events[i].data.fd, eventLoop->thread_name);
            channel_event_activate(eventLoop, epollDispatcherData->events[i].data.fd, EVENT_WRITE); // 触发 channel 写事件
        }
    }

    return 0;
}

// 关闭 epoll
void epoll_clear(struct event_loop *eventLoop)
{
    epoll_dispatcher_data *epollDispatcherData = (epoll_dispatcher_data *)eventLoop->event_dispatcher_data;

    free(epollDispatcherData->events);
    close(epollDispatcherData->efd);
    free(epollDispatcherData);
    eventLoop->event_dispatcher_data = NULL;

    return;
}